import pygame
import random

from CEnemy import CEnemy
from CPickup import CPickup
from CMapGenerator import CMapGenerator
from CTextureManager import CTextureManager

class CMap(object):
    
    TILE_SIZE = 16
    
    MAX_SPACE_SEARCH_ITERATIONS = 100
    
    COLUMNS = 40 
    ROWS = 26
    
    # Our blank map to be filled by the map generator
    walls = []

    def __init__( self , player , level ):
        """ Constructor. """
        
        # Load our level tile textures
        if( CTextureManager.IsLoadedTexture("Wall") == False):
            self.wall = CTextureManager.LoadTexture( "img/wall.gif" , "Wall")
        else:
            self.wall = CTextureManager.GetTexture("Wall")
            
        if( CTextureManager.IsLoadedTexture("Floor") == False):
            self.floor = CTextureManager.LoadTexture( "img/floor.gif" , "Floor")
        else:
            self.floor = CTextureManager.GetTexture("Floor")
            
        if( CTextureManager.IsLoadedTexture("Stairs") == False):
            self.stairs = CTextureManager.LoadTexture( "img/stairs.gif" , "Stairs")
        else:
            self.stairs = CTextureManager.GetTexture("Stairs")

        
        # Blank shadow map
        self.cleared = self.get_blank_map()
        
        # Current level ( from CGame )
        self.mCurrentLevel = level
        
        # Grab our player reference
        self.mPlayer = player
        
        # Holds all the enemies in the level.
        self.mEnemies = list()
        
        # Holds all pickups in the level
        self.mPickups = list()
        
        # Generate our map
        mg = CMapGenerator( self.COLUMNS , self.ROWS , 1 )
        self.walls = mg.GenerateMap() 
        
        # Generate enemies for the level
        self.GenerateEnemies(5)
        
        # Generate player pick-ups
        self.GeneratePickups(7)
        
        # Set up our player starting point
        self.mStartingPoint = mg.GetPlayerStart()
        self.mPlayer.SetWorldPos( self.mStartingPoint )
        self.current = self.get_blank_map()
    
    def get_blank_map(self):
        ''' Returns a map with all values set to 0
        '''
        map = []
        for row in range(self.ROWS):
                        row = []
                        for col in range(self.COLUMNS):
                                row.append(0)
                        map.append(row)
        return map
    
    def clear_block(self, position):
        ''' Given the current position of the player, sets the current square to completely cleared, 
                and the squares nearby to partially cleared.
        '''
        x, y = position #Here I am

        for row in range(self.ROWS): #Wherever I was, suddenly I see shadows, everywhere
            for col in range(self.COLUMNS):
                if self.cleared[row][col] == 2:
                    self.cleared[row][col] = 1
        col = x
        row = y            
        self.cleared[row][col] = 2 #I can see clearly now
        if row < self.ROWS-1:
            self.cleared[row+1][col] = 2
            if col > 0:
                self.cleared[row+1][col-1] = 2
            if col < self.COLUMNS-1:
                self.cleared[row+1][col+1] = 2
        if row > 0:
            self.cleared[row-1][col] = 2
            if col > 0:
                self.cleared[row-1][col-1] = 2
            if col < self.COLUMNS-1:
                self.cleared[row-1][col+1] = 2
        if col < self.COLUMNS-1:
            self.cleared[row][col+1] = 2
        if col > 0:
            self.cleared[row][col-1] = 2
    
    
    
    def draw(self , inScreen):
        """ Draws all objects in our map: Walls, enemies, etc. """
        
        # Draw walls
        for row in range(self.ROWS):
            for col in range (self.COLUMNS):
                if self.walls[row][col] == '#':
                    inScreen.blit(self.wall, ((col)*16, (row)*16))
                elif self.walls[row][col] == '%':
                    inScreen.blit( self.stairs , ( ( col*16 ) , ( row * 16 ) ) )
                else:
                    inScreen.blit(self.floor, ((col)*16, (row)*16))
                    
        # Draw Pickups
        for pickup in self.mPickups:
            pickup.draw( inScreen )
            
        # Draw enemies
        for enemy in self.mEnemies:
            enemy.draw( inScreen )
            

            
        
        
    def isSolidSpace(self , ( x , y ) ):
        """ Check to see if a given space in our map is solid """
        
        # Wall Check
        if( self.walls[y][x] == '#' ) : 
            return True
        # Enemy Check
        elif( self.isEnemyInSpace( ( x , y ) ) == True ):
            return True
        # Player Check
        elif( self.mPlayer.GetWorldPos() == ( x , y ) ):
            return True
        else:
            return False
        
    def isStairSpace( self , ( x , y ) ):
        """ Returns true if space contains exit stairs, false if it does not. """
        if( self.walls[x][y] == '%'):
            return True
        else:
            return False
    
    def GetRandomEmptySpace(self):
        """ Gets a random empty space by searching random coordinates until one returns empty.
            You can set the limit on how many times you are willing to search for an empty space by adjusting CMap.MAX_SPACE_SEARCH_ITERATIONS. """
        i = 0
        while( i <= CMap.MAX_SPACE_SEARCH_ITERATIONS ):
            
            # Create a randomly generated tuple that will create a coordinate somewhere inside of our wall map
            coord = ( random.randint( 0 , len( self.walls[0] ))-1 , random.randint( 0 , len( self.walls ))-1 ) 
            
            # If we find an empty space return it
            if( self.isSolidSpace( coord ) == False):
                return coord
            
            i += 1
            
    def GenerateEnemies(self , numEnemies ):
        """ Generate a set number of enemies for our level. """
        
        for i in range( numEnemies ) :

            # Add our boss to the last level
            if( i == numEnemies-1 and self.mCurrentLevel == 10 ):
                self.mEnemies.append( CEnemy( "Ghost" , self.GetRandomEmptySpace() , self , i ) )
            
            enemyType = random.randint(0,1)
            
            if( enemyType == 0 and self.mCurrentLevel > 2 ):
                self.mEnemies.append( CEnemy( "Slime" , self.GetRandomEmptySpace() , self , i ) )
            else:
                self.mEnemies.append( CEnemy( "FlameTail" , self.GetRandomEmptySpace() , self , i ) )
                
    def GeneratePickups(self , numPickups ):
        """ Generate a set number of pickups for our level. """
        
        for i in range(numPickups):
            
            # Give us a small (1/6) chance of spawning the sword once per level
            if( i == numPickups-1 and self.mPlayer.mCurrentWeapon.mName != "Goldleaf"):
                randomnumber = random.randint(1,3)
                if( randomnumber == 3):
                    self.mPickups.append( CPickup("GoldSword" , self.GetRandomEmptySpace() , self , i , i+1))
                    break
            
            pickupType = random.randint(0,1)
        
            if( pickupType == 0):
                self.mPickups.append( CPickup("Gold" , self.GetRandomEmptySpace() , self , i , i+1))
            elif( pickupType == 1):
                self.mPickups.append( CPickup("Health" , self.GetRandomEmptySpace() , self , i , i+1))
            else:
                print("Invalid pickup type!")
                #do nothing
                
        return
            
    def isEnemyInSpace( self , ( x , y ) ):
        """ Check to see if there is an enemy in the given space. """
        
        for e in self.mEnemies:
            if( e.GetWorldPos() == ( x , y ) ):
                return True
            
    def isPickupInSpace(self , ( x , y ) ):
        """ Check to see if there is a pickup in the space. If there is, return it. """
        for p in self.mPickups:
            if( p.GetWorldPos() == ( x , y ) ):
                return True
            
    def GetEnemyInSpace(self , ( x , y ) ):
        """ Get an enemy if it resides in a given space. If there is no enemy then we return None. """
        for e in self.mEnemies:
            if( e.GetWorldPos() == ( x , y ) ):
                return e
            
    def GetPickupInSpace(self , ( x , y ) ):
        """ Get a pickup if it resides in a given space. If there is no pickup then we return None. """
        for p in self.mPickups:
            if( p.GetWorldPos() == ( x , y )):
                return p
            
    def GetEnemies(self):
        """ Accessor to our enemy list for use elsewhere. """
        return self.mEnemies
    
    def GetPickups(self):
        """ Accessor to get pickups. """
        return self.mPickups
    
    def GetPlayer(self):
        """ Accessor to the player. """
        return self.mPlayer
            
            
        
                
            
        
         

